#include <QThread>
#include "rtxtfilemodel.h"
#include "rconstdifinition.h"

RTxtFileModel::RTxtFileModel(REngine& engine, QObject *parent) :
    RFileModel(engine, parent)
{
}


void RTxtFileModel::chapters(QStringList& chapterList) {
    chapterList.clear();
    if (m_file_chapter_line.count()) {
        //If already exist, just reuse old one
        if (m_file_chapter.count() == m_file_chapter_line.count()) {
            chapterList<<m_file_chapter;
        }
        else {
            m_file_chapter.clear();
            for (int i = 0; i < m_file_chapter_line.count(); i++) {
                m_file_chapter.append(data(m_file_chapter_line[i]).toString());
            }
            chapterList<<m_file_chapter;
        }
    }
}

int RTxtFileModel::lineNumberOfChapter(int chapterIndex) {
    int lineNumber = KInvalidId;
    if (chapterIndex >=0 && chapterIndex <m_file_chapter_line.count()) {
        lineNumber = m_file_chapter_line[chapterIndex];
    }
    return lineNumber;
}

int RTxtFileModel::currentChapterIndex() {
    int lineNum = m_engine.lastLineNumber(m_file->fileName());
    int index = -1;
    for (int i = 0; i < m_file_chapter_line.count(); i++) {
        if (m_file_chapter_line[i] > lineNum) {
            break;
        }
        index = i;
    }
    return index;
}

bool RTxtFileModel::initFileInfo() {
    //Do nothing now
    return true;
}

bool RTxtFileModel::analyzeFile() {
    bool result = false;
    m_file_line_pos.clear();
    int lineNum = 0;
    if (m_file->isReadable()) {
        //seek to the beginning of file
        if (m_file->seek(0)) {
            //System codec could not use QTextStream to get pos
            qDebug()<<"Analyse with file"<<m_file->fileName();
            qDebug()<<"currentThreadId"<<QThread::currentThreadId();
            //Use file to read each line and store the postion
            int fetchMore;
            qDebug()<<"m_codec:"<<(quint32)m_codec;
            newLineCharLaw(*m_codec, fetchMore);
            m_file_line_pos[0] = 0;
            QByteArray array = m_file->readLine();
            lineNum = 1;
            QList<QString> chapterKeys;
            m_engine.chapterKeys(m_codec->name(), chapterKeys);
            while (!array.isNull()) {
                if (fetchMore > 0) {
                    array.append(m_file->read(fetchMore));
                }

                //For some codec like UTF16 the read line may not really a line
                if (lastCharIsNewLine(array, *m_codec)) {
                    //Check whether current line is the chapter
                    if (chapterKeys.length()) {
                        QString unicodeStr = m_codec->toUnicode(array.left(KChapterCheckingMaxLen));

                        //Check Chapter
                        for (int i = 0; i < chapterKeys.length(); i++) {
                            QRegExp regExp(chapterKeys[i]);
                            int index = regExp.indexIn(unicodeStr);
                            if (index != -1) {
                                m_file_chapter_line.append(lineNum-1);
//                                qDebug()<<"Find chapter on line "<<lineNum<<":"<<unicodeStr;
                                break;
                            }
                        }
                    }
                    m_file_line_pos[lineNum] = m_file->pos();
                    if (lineNum<100) {
                        qDebug()<<"Store lineNum"<<lineNum
                               <<"pos"<<m_file_line_pos[lineNum];
                    }
                    m_file->seek(m_file_line_pos[lineNum]);
                    ++lineNum;
                }
                else {
                    // qDebug()<<"last char is not new line, continue reading";
                }

                array = m_file->readLine();
            }

            result = true;
        }
        else {
            qDebug()<<"ERROR::Could not seek file to 0";
        }
    }
    else {
        qDebug()<<"ERROR::file is not readable";
    }
    return result;
}

bool RTxtFileModel::openFile(const QString& fileName) {
    m_file_line_pos.clear();
    bool success(false);
    if (m_file) {
        m_file->close();
        delete m_file;
        m_file = NULL;
    }

    qDebug()<<"RTxtFileModel::Opening file:"<<fileName;
    m_file = new QFile(fileName);
    success = m_file->open(QIODevice::ReadOnly);
    if (success) {
        qDebug()<<"File opened";
        QString codec = m_engine.fileCodec(fileName);
        //When codec is set to auto, need to auto detect codec
        if (codec == KCodecAuto || codec == KCodecNotAvailable) {
            //First use QTextStream to auto detect
            QTextStream stream(m_file);
            stream.setAutoDetectUnicode(true);
            QString str = stream.read(4096);
            if (str.length()) {
                qDebug()<<"Read line"<<str<<"Codec"<<stream.codec()->name();
                //When codec is "System", on N950 the string could not be decoded.
                //We need to use libenca to detect codec
                if (stream.codec()->name() == KCodecSystem) {
                    m_file->seek(0);
                    QByteArray text = m_file->read(4096);
                    bool useDefaultCodec;
                    m_codec = m_engine.codecForString(text, useDefaultCodec);
                    if (m_codec) {
                        if (useDefaultCodec) {
                            qDebug()<<"ERROR::Could not find suitable codec for file:"<<fileName
                                   <<"use default one"<<m_codec->name();
                            //Only set default codec when first time open
                            if (m_engine.fileExistInDb(fileName)) {
                                qDebug()<<"File already opened before, do not set use default codec";
                                m_open_result = REngine::OpenFileSuccess;
                            }
                            else {
                                m_open_result = REngine::OpenFileSuccessWithDefaultCodec;
                            }
                        }
                        else {
                            m_open_result = REngine::OpenFileSuccess;
                        }
                    }
                    else {
                        qDebug()<<"Find codec to decode file:"<<m_codec->name();
                        m_open_result = REngine::OpenFileFailed;
                    }
                }
                else {
                    qDebug()<<"Use stream codec"<<stream.codec()->name();
                    m_codec = stream.codec();
                    m_open_result = REngine::OpenFileSuccess;
                }
            }
            else {
                qDebug()<<"Could not read line";
                m_open_result = REngine::OpenFileFailed;
            }
        }
        else {
            m_codec = QTextCodec::codecForName(codec.toLatin1());
            qDebug()<<"set m_codec to "<<m_codec->name();
            m_open_result = REngine::OpenFileSuccess;
        }
    }
    else {
        qDebug()<<"RTxtFileModel::Open file failed:"<<m_file->errorString();
        m_open_result = REngine::OpenFileFailed;
    }

    return success;
}

bool RTxtFileModel::saveFileLinePosition() {
    m_engine.saveFileLinePosition(m_file->fileName(), m_file_line_pos, m_file_chapter_line);
    return true;
}

bool RTxtFileModel::readFileLinePosition() {
    return m_engine.fileLinePosition(m_file->fileName(), m_file_line_pos, m_file_chapter_line);
}

QVariant RTxtFileModel::data(int row) const {
    if (row < m_file_line_pos.count()) {
        if (m_file->seek(m_file_line_pos[row])) {
            QTextStream stream(m_file);
            stream.setCodec(m_codec);
            stream.setAutoDetectUnicode(true);
            QString str = stream.readLine(KLineMaxLength);
            if (str.length() || !m_file->atEnd()) {
                qDebug()<<"Read str row"<<row
                       <<"pos"<<m_file_line_pos[row]
                      <<"length"<<str.length()<<str;
                return str+KNewLine;
            }
            else {
                qDebug()<<"read file line failed, line number"<<row
                       <<"Position"<<m_file_line_pos[row]
                      <<m_file->errorString();
            }
        }
        else {
            qDebug()<<"could not seek to position/line"<<m_file_line_pos[row]<<row;
        }
    }
    else {
        qDebug()<<"row number is too large:row/max"<<row<<m_file_line_pos.count();
    }
    return QString(KNewLine);
}
